<?php

namespace app\api\controller;

use app\common\controller\Api;
use app\api\validate\Trades as TradesValidate;
use app\common\model\ShareStrategy;
use app\common\model\Config;
use app\common\model\Stock;
use app\common\model\Strategy;
use app\common\model\StrategyTransaction;
use app\common\model\UserSelect;
use think\Db;
use think\Log;

class Trade extends Api
{
    // 无需登录的接口,*表示全部
    protected $noNeedLogin = ['*'];
    // 无需鉴权的接口,*表示全部
    protected $noNeedRight = ['*'];

    //获取股票信息
    protected function stockInfo($data){
        $returnData = getStockInfo($data);
        return $returnData;
    }
    
    //添加自选
    public function addSelect(){
        $userInfo = $this->auth->getUser();
        $allNo = $this->request->post('allNo');
        $userSelectInfo = UserSelect::where(['all_no'=>$allNo,'user_id'=>$userInfo->id])->find();
        if( $userSelectInfo ){
            $this->error('股票已添加自选');
        }
        $stockInfo = $this->stockInfo($allNo)[$allNo];
        UserSelect::create([
            'user_id'=>$userInfo->id,
            'all_no'=>$stockInfo['all_no'],
            'no'=>$stockInfo['no'],
            'name'=>$stockInfo['name'],
        ]);
        $this->success('添加成功');
    }

    //删除自选
    public function delSelect(){
        $userInfo = $this->auth->getUser();
        $id = $this->request->post('id');
        $userSelectInfo = UserSelect::where(['id'=>$id,'user_id'=>$userInfo->id])->find();
        if( !$userSelectInfo ){
            $this->error('没有找到自选股票');
        }
        $userSelectInfo->delete();
        $this->success('删除成功');
    }

    //获取自选列表
    public function selectList(){
        $userInfo = $this->auth->getUser();
        $list = UserSelect::where(['user_id'=>$userInfo->id])->select();
        $allNoList = $list->column('all_no');
        $stockList = $this->stockInfo($allNoList);
        $list = $list->toArray();
        foreach ( $list as $key => $info ){
            
            $list[$key]['price'] = $stockList[$info['all_no']]['price'];
        }
        
        $this->success('获取成功',$list);
    }

    //推荐列表
    public function recommend(){
        $noList = Config::getVal(['recommend'])['recommend'];
        $noList = array_filter(explode("\r\n",$noList));
        $allNoList = Stock::whereIn('no',$noList)->select()->column('all_no');
        $stockList = $this->stockInfo($allNoList);
        $this->success('获取成功',$stockList);
    }
    
    protected function check($allNo,$num,$conList){
        //验证是否在交易时间内
        if( !isPayTime() ){
            $this->error('当前时间不在交易时间段内');
        }

        $stockInfo = $this->stockInfo($allNo)[$allNo]??[];
        if( empty($stockInfo) ){
            $this->error('没有找到股票信息');
        }
        if( $stockInfo['f'] > 9.5 ){
            $this->error('涨幅额度大于9.5无法买入');
        }
        if( $num < $conList['min_buy_num'] ){
            $this->error('最低买入数量为：'.$conList['min_buy_num']);
        }
        if( !is_int($num / 100) ){
            $this->error('购买数量必须是100的倍数');
        }

        return $stockInfo;
    }

    //获取是否在交易时间段
    public function getIsPayTime(){
        if( isPayTime() ){
            $this->success('当前时间可交易',true);
        }
        $this->error('当前时间不在交易时间段内',false);
    }

    //创建策略
    public function createStrategy(){
        $params = $this->request->post();
        $validate = new TradesValidate;
        if(!$validate->scene('createStrategy')->check($params)){
            return $this->error($validate->getError());
        }
        
        if( !isPayTime() ){
            $this->error('当前时间不在交易时间段内');
        }
        
        $userInfo = $this->auth->getUser();

        if( empty($userInfo->real_name) ){
            $this->error('请先设置实名信息再操作！');
        }

        $strategyInfo = ShareStrategy::where(['user_id'=>$userInfo->id,'all_no'=>$params['allNo'],'status'=>1])->find();
        if( $strategyInfo ){
            $this->error('已有创建策略');
        }
        //获取股票信息
        $stockname = Stock::where('all_no',$params['allNo'])->value('name');
        if(isset($params['id'])) unset($params['id']);
        //获取金额信息
        $conList = Config::getVal(['min_buy_num','management_expense','add_warehouse']);
        //保证金
        $earnestMoney = $params['price'] * $params['num'] / 10;
        //管理费
        $managementExpense = $params['isAuto'] == 1 ? $earnestMoney * $conList['management_expense'] * 0.01 * 10: 0;
        //建仓费
        $addWarehouse = $earnestMoney * 10 * $conList['add_warehouse'];
        
        if( ($earnestMoney + $managementExpense + $addWarehouse) > $userInfo->money ){
            $this->error('余额不足');
        }

        Db::startTrans();
        try{
            //组装数据
            $params['user_id']          = $userInfo->id;
            $params['name']             = $stockname;
            $params['all_no']           = $params['allNo'];
            $params['total_lever_num']  = $params['num'];
            $params['is_auto']          = $params['isAuto'];
            $params['total_earnest']    = $params['price'] * $params['num'] / 10;

            //创建新策略
            $strategyInfo = new ShareStrategy();
            $strategyInfo->allowField(true)->save($params);

            //新增交易记录
            $strategyTransaction                = new StrategyTransaction();
            $strategyTransaction->user_id       = $userInfo->id;
            $strategyTransaction->strategy_id   = $strategyInfo->id;
            $strategyTransaction->buy_price     = $params['price'];
            $strategyTransaction->lever_num     = $params['num'];
            $strategyTransaction->type          = 'new';
            $strategyTransaction->name          = $stockname;
            $strategyTransaction->no            = $params['allNo'];
            $strategyTransaction->buy_time      = time();
            $strategyTransaction->earnest       = $params['price'] * $params['num'] / 10;
            $strategyTransaction->save();

            //扣除余额
            updateMoney($userInfo,-$earnestMoney,'保证金');
            //建仓费
            if( $addWarehouse > 0 ){
                updateMoney($userInfo,-$addWarehouse,'建仓费');
            }
            if( $managementExpense > 0 ){
                updateMoney($userInfo,-$managementExpense,'管理费');
            }

            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            $this->error('生成策略失败：'.$e->getMessage());
        }
        $this->success('生成策略成功');
    }

    //获取策略列表
    public function getList()
    {
        
        $userInfo = $this->auth->getUser();
        $status = $this->request->get('status',1);
        
        $strategyInfo = ShareStrategy::where(['user_id'=>$userInfo->id,'status'=>$status,'total_lever_num'=>['>',0]])->select();

        //检查是否需要自动平仓
        //$this->autoPay($userInfo,$strategyInfo);
        if( $status == 1 ){
            //检查是否需要自动平仓
            $this->autoPay($userInfo,$strategyInfo);
            //var_dump($strategyInfo);die;
            //获取平均成交价
            $ids = $strategyInfo->column('id');
            $list = StrategyTransaction::where(['strategy_id'=>['in',$ids], 'user_id'=>$userInfo->id, 'buy_price'=>['>',0]])->order('createtime', 'asc')->column('id,buy_price,strategy_id');
            $new_arr = array_reduce($list, function($result, $item) {
                // 如果策略ID已存在于新数组中，将买入价格相加
                if (isset($result[$item['strategy_id']])) {
                    $result[$item['strategy_id']]['total_price'] += $item['buy_price'];
                    $result[$item['strategy_id']]['count']++;
                } else {
                    // 如果策略ID不存在于新数组中，添加新元素
                    $result[$item['strategy_id']] = [
                        'total_price' => $item['buy_price'],
                        'count' => 1,
                    ];
                }
                return $result;
            }, []);
            
            
            //var_dump($strategyInfo);die;
            $newArray = array_map(function($value) {
                return round($value['total_price'] / $value['count'], 2);
            }, $new_arr);
            
            
            
            foreach($strategyInfo as $strategy){
                //$strategy['buy_price'] = $newArray[$strategy['id']] ?? 0;//平均买价
                $strategy['buy_price'] =round (intval($strategy['total_earnest'])/intval($strategy['total_lever_num'])*10,2);
                
                
                $strategy['pay_price'] = "0.00";//卖价
                $strategy['buy_time_text'] = date('Y-m-d H:i:s',$strategy['createtime']);//购买时间
                $strategy['no'] = $strategy['all_no'];
            }
        
       // dump($strategyInfo);die;
            $this->success('获取成功',$strategyInfo,1,null,[],['money'=>$userInfo->money]);
        }

        //获取历史记录
        
        $list = StrategyTransaction::where('user_id',$userInfo->id)->select()->toArray();
        foreach($list as $k => $v){
            !empty($v['buy_time']) ? $list[$k]['buy_time_text'] = date('Y-m-d H:i:s',$v['buy_time']) : $list[$k]['buy_time_text'] = 'null';
            !empty($v['pay_time']) ? $list[$k]['pay_time_text'] = date('Y-m-d H:i:s',$v['pay_time']) : $list[$k]['pay_time_text'] = 'null';
        }
        //$list = array_merge($list,$strategyInfo->toArray());
        $this->success('获取成功',array_values($list),1,null,[],['money'=>$userInfo->money]);
    }
    /**
     * 自动平仓，触发条件：1.爆仓，账户余额不够亏损，强制平仓该股票
     */
    protected function autoPay($userInfo,$strategyInfo)
    {
        if( !isPayTime() ){
            //$this->error('当前时间不在交易时间段内');
            return;
        }
       
        //获取所有的策略ID
        $ids = $strategyInfo->column('id');
      
        //所持有股票编号
        $allNoList = $strategyInfo->column('all_no');
        //用户余额
        $before = $userInfo->money;
        
           
           
        if($before <= 0){
            return;
        }
        $strategyInfo = $strategyInfo->toArray();
        
        
        $list = StrategyTransaction::where(['strategy_id'=>['in',$ids], 'user_id'=>$userInfo->id, 'buy_price'=>['>',0]])->order('createtime', 'asc')->select();
        //获取各种手续费金额信息
        $conList = Config::getVal(['commission','stamp_duty','transfer_fee']);
        //获取股票信息
        $stockInfo = $this->stockInfo($allNoList);
        
        foreach($strategyInfo as $key => $value){
           
            //平均买价
            $buy_price = floatval(floatval($value['total_earnest'])/intval($value['total_lever_num'])*10);
            
            //每股盈亏
            $profit = floatval($stockInfo[$value['all_no']]['price']) - $buy_price;
             
            //总盈亏
            $sumProfit = $profit * intval($value['total_lever_num']);
            
            //判断保证金有没有亏完,小于等于0就亏完了
            $loss = bcadd(strval($value['total_earnest']),strval($sumProfit),2);
            
            //判断余额够亏损吗
            $after = bcadd(strval($before),$loss,2);
            
            //用户余额不够亏损就强制平仓这只股票
            if($loss < 0 && $after < 0){
                //var_dump($after);die;
                $strategyModel = new ShareStrategy();
                
                //组装平仓交易数据
                $strategyTransaction                = new StrategyTransaction();
                //var_dump($after);die;
                $transaction = array();
                $transaction['user_id']       = $userInfo->id;
                $transaction['strategy_id']   = $value['id'];
                $transaction['type']          = 'autoReduce';
                $transaction['buy_price']     = $buy_price;
                $transaction['pay_price']     = floatval($stockInfo[$value['all_no']]['price']);
                $transaction['lever_num']     = $value['total_lever_num'];
                $transaction['name']          = $value['name'];
                $transaction['no']            = $value['all_no'];
                //保证金记录
                $transaction['earnest']       = $value['total_earnest'];
                $transaction['pay_time']      = time();
                $transaction['buy_time']      = $value['createtime'];
                $transaction['createtime']    = time();
                $transaction['updatetime']    = time();
               
                
                //组装平仓策略数据
                $value['total_earnest'] = 0;
                $value['total_lever_num'] = 0;
                $value['can_use_num'] = 0;
                $value['status'] = 0;
                $value['updatetime'] = time();
                Db::startTrans();
                try {
                    //修改策略数据 
                    $strategyModel->update($value);
                    //添加历史交易数据
                    $strategyTransaction->insert($transaction);
                    //修改用户余额
                    updateMoney($userInfo,floatval($before)*-1,'自动平仓');
                    Db::commit();
                }catch (\Exception $e){
                    Db::rollback();
                    Log::error("自动平仓失败:".$e->getMessage());
                }
            }
            return;
        }
        return;
    }

    //追加股数
    public function addNum(){
        
        if( !isPayTime() ){
            $this->error('当前时间不在交易时间段内');
        }
        
        $params = $this->request->post();
        $validate = new TradesValidate;
        if(!$validate->scene('addNum')->check($params)){
            return $this->error($validate->getError());
        }
        $userInfo = $this->auth->getUser();
        $strategyInfo = ShareStrategy::where(['user_id'=>$userInfo->id,'id'=>$params['id'],'status'=>1])->find();
        if( !$strategyInfo ){
            $this->error('没有找到策略信息');
        }

        //获取股票信息
        $stockInfo = getRealTimeStockInfo($strategyInfo->all_no)[$strategyInfo->all_no];

        //获取金额信息
        $conList = Config::getVal(['min_buy_num','management_expense','add_warehouse']);
        //保证金
        $earnestMoney = $stockInfo['price'] * $params['num'] / 10;
        //管理费
        $managementExpense = $strategyInfo['is_auto'] == 1 ? $earnestMoney * $conList['management_expense'] * 0.01 * 10 : 0;
        //建仓费
        $addWarehouse = $earnestMoney * 10 * $conList['add_warehouse'];
        if( ($earnestMoney + $managementExpense + $addWarehouse) > $userInfo->money ){
            throw new \Exception('余额不足');
        }
        
        Db::startTrans();
        try{
            //修改策略数据
            $strategyInfo->total_lever_num += $params['num'];
            $strategyInfo->total_earnest += $params['num'] * $stockInfo['price'] / 10;
            $strategyInfo->createtime = time();
            $strategyInfo->save();

            //创建策略交易记录
            $strategyTransaction                = new StrategyTransaction();
            $strategyTransaction->user_id       = $userInfo->id;
            $strategyTransaction->strategy_id   = $strategyInfo->id;
            $strategyTransaction->buy_price     = $stockInfo['price'];
            $strategyTransaction->lever_num     = $params['num'];
            $strategyTransaction->name          = $strategyInfo['name'];
            $strategyTransaction->no            = $strategyInfo['all_no'];
            $strategyTransaction->buy_time      = time();
            $strategyTransaction->earnest       = $stockInfo['price'] * $params['num'] / 10;
            $strategyTransaction->save();

            //扣除余额
            updateMoney($userInfo,$earnestMoney * -1,'保证金');
            if( $addWarehouse > 0 ){
                updateMoney($userInfo,$addWarehouse * -1,'建仓费');
                //交易佣金
                updateMoney($userInfo,$stockInfo['price'] * $params['num'] * $conList['commission'] * 0.01 *-1,'交易佣金');
            }
            if( $managementExpense > 0 ){
                updateMoney($userInfo,$managementExpense * -1,'管理费');
            }

            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            $this->error('补充失败：'.$e->getMessage());
        }
        $this->success('补充成功');
    }

    //平仓
    public function pay(){
        
        if( !isPayTime() ){
            $this->error('当前时间不在交易时间段内');
        }
        
        $params = $this->request->post();
        $validate = new TradesValidate;
        if(!$validate->scene('pay')->check($params)){
            return $this->error($validate->getError());
        }
        
        
        $userInfo = $this->auth->getUser();
        $strategyInfo = ShareStrategy::where(['user_id'=>$userInfo->id,'id'=>$params['id'],'status'=>1])->find();
        
        //var_dump($strategyInfo);die;
        if( !$strategyInfo ){
            $this->error('没有找到策略信息');
        }
        
        if($strategyInfo['can_use_num'] < $params['num']){
            $this->error('当前可交易数量不足',[],403);
        }
        
        //获取金额信息
        $conList = Config::getVal(['commission','stamp_duty','transfer_fee']);

        //获取股票信息
        $stockInfo = getRealTimeStockInfo($strategyInfo->all_no)[$strategyInfo->all_no];

        Db::startTrans();
        try {
            $strategy = array();
            //$strategyInfo->total_lever_num += $params['num'];
            //$strategyInfo->total_earnest += $params['num'] * $stockInfo['price'] / 10;
            //修改策略数据
            if((intval($strategyInfo->total_lever_num) - intval($params['num'])) <= 0){
                $strategy['status'] = 0;
                //$strategyInfo->save();
            }
            //策略表里总保证金要扣除的保证金
            $earnest = intval($strategyInfo->total_earnest)/intval($strategyInfo->total_lever_num)*intval($params['num']);
            $strategy['id'] = $strategyInfo->id;
            $strategy['total_lever_num'] = intval($strategyInfo->total_lever_num) - intval($params['num']);
            $strategy['total_earnest'] =intval($strategyInfo->total_earnest) - $earnest;
            $strategy['can_use_num'] = intval($strategyInfo->can_use_num) -intval($params['num']);
            ShareStrategy::update($strategy);
            //var_dump($earnest);die;
            //持有股票的保证金平仓后要退回到可用资金
            updateMoney($userInfo,$earnest,'保证金');
            
            $strategyInfo->save();
            $transaction = array();
            //创建策略交易记录
            $strategyTransaction                = new StrategyTransaction();
            $transaction['user_id']       = $userInfo->id;
            $transaction['strategy_id']   = $strategyInfo->id;
            $transaction['type']          = 'reduce';
            $transaction['buy_price']     = floatval($strategyInfo->total_earnest)/floatval($strategyInfo->total_lever_num)*10;
            $transaction['pay_price']     = $stockInfo['price'];
            $transaction['lever_num']     = $params['num'];
            $transaction['name']          = $strategyInfo->name;
            $transaction['no']            = $strategyInfo->all_no;
            //保证金记录
            $transaction['earnest']       = $earnest;
            $transaction['pay_time']      = time();
            $transaction['buy_time']      = $strategyInfo->createtime;
            $transaction['createtime']    = time();
            $transaction['updatetime']    = time();
            $strategyTransaction->insert($transaction);
            //每股盈亏
            $profit = floatval($stockInfo['price']) - floatval($strategyInfo->total_earnest)/floatval($strategyInfo->total_lever_num)*10;
            //平仓后的钱
            updateMoney($userInfo,$profit * intval($params['num']),'盈亏');
            //交易佣金
            updateMoney($userInfo,floatval($stockInfo['price']) * intval($params['num']) * floatval($conList['commission']) * -1,'交易佣金');
            //印花税
            updateMoney($userInfo,floatval($stockInfo['price']) * intval($params['num']) * floatval($conList['stamp_duty']) * -1,'印花税');
            //过户费
            updateMoney($userInfo,floatval($stockInfo['price']) * intval($params['num']) * floatval($conList['transfer_fee']) * -1,'过户费');
            //记录累计盈亏
            updateCumulative($userInfo,$profit * intval($params['num']),'累计盈亏');
            
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            $this->error('平仓失败',$e->getMessage());
        }
        $this->success('平仓成功');
    }
    
    // 判定平仓可用股票标准
protected function checkIsUse($buy_time){
    return intval(date('Y-m-d')) > intval(date('Y-m-d',$buy_time));
}

    //计划任务
    public function jhrw()
    {
/*        
        $stocks = StrategyTransaction::where(['type'=>'add','lever_num'=>['>',0],'buy_time'=>['<',(time()-86400)],'is_use'=>1])->column('id,strategy_id,lever_num');
        $levers = array_reduce($stocks, function($result, $item) {
            if (isset($result[$item['strategy_id']])) {
                $result[$item['strategy_id']] += $item['lever_num'];
            } else {
                $result[$item['strategy_id']] = $item['lever_num'];
            }
            return $result;
        }, []);
         
        $strategys = ShareStrategy::where(['id'=>['in',array_column($stocks, 'strategy_id')],'status'=>1])->select()->toArray();
*/        
        $stocks1 = ShareStrategy::where(['status'=>1])->select()->toArray();
        
        foreach ($stocks1 as $key => $value){
            $keyong = 0;
            $jiaoyi = StrategyTransaction::where(['strategy_id'=>$value['id']])->column('id,strategy_id,lever_num,buy_time,type');
            foreach ($jiaoyi as $k => $val){
                //if(checkIsUse($val['buy_time'])){
                if(date('Y-m-d') > date('Y-m-d',$val['buy_time'])){
                    //echo json_encode($val);
                    if($val['type'] == 'add' || $val['type'] == 'new'){
                        
                        $keyong += $val['lever_num'];
                    }else{
                        $keyong -= $val['lever_num'];
                    }
                    //echo $keyong;
                }
            }
            //echo $val['type'];
            //echo '<br>';
            //echo checkIsUse($val['buy_time']);
           $stocks1[$key]['can_use_num'] = $keyong;
           
        }
        //echo json_encode($stocks1);
        //die;
/*        
        // 更新数据库中的股票信息
        $model = new ShareStrategy();
        
        foreach($strategys as $key => $v){
            $strategys[$key]['can_use_num'] += $levers[$v['id']];
        }

        foreach($stocks as $key => $stock){
            $stocks[$key]['is_use'] = 0;
        }
*/
        Db::startTrans();
        try {
            //StrategyTransaction::saveAll($stocks);
            //ShareStrategy::saveAll($stocks1);
            
            foreach ($stocks1 as $key => $value){
                
                ShareStrategy::update([
                    'id'=>$value['id'],
                    'can_use_num'=>$value['can_use_num']
                    ]);
            }
            echo '添加可用成功';
            Db::commit();
        }catch (\Exception $e){
            Db::rollback();
            Log::error("添加可用失败:".$e->getMessage());
        }
    }
    
    //获取统计信息
    public function getStatistics(){
        $userInfo = $this->auth->getUser();
        $strategyList = ShareStrategy::where(['user_id'=>$userInfo->id,'status'=>1])->select();
        $ids = $strategyList->column('id');
        $allNoList = $strategyList->column('all_no');
        $stockList = getRealTimeStockInfo($allNoList);
/*
        $data = StrategyTransaction::where(['user_id'=>$userInfo->id,'strategy_id'=>['in',$ids]])->column('id,lever_num,no,buy_price,type,earnest');

        $result = array_reduce($data, function($carry, $item) {
            $carry[$item['no']][] = $item;
            return $carry;
        }, []);
*/
        //总亏损     平均买价      总盈亏       市值                总保证金
       $totalLoss = $buy_price = $sum_income = $market_value = $net_assets =0;

        foreach ($strategyList as $key => $value){
            $buy_price = $value->total_earnest/$value->total_lever_num*10;
            $price = $stockList[$value->all_no]['price'];
            $sum_income += ($price - $buy_price)*$value->total_lever_num;
            $market_value += $price*$value->total_lever_num;
            $net_assets += $value->total_earnest;
        }
        $net_assets = strval($net_assets);
        $sum_income = strval($sum_income);
        //若总亏损大于总保证金，可用余额要相应变动
        if(bcadd($net_assets,$sum_income,2) < 0){
            $totalLoss = bcadd($net_assets,$sum_income,2);
        }
        //file_put_contents(__DIR__.'\\observe.log',$net_assets.'|'.$sum_income,FILE_APPEND);
        $money = bcadd(strval($userInfo->money),$totalLoss,2);
        $data = [
            'net_assets'=>$money + $sum_income + $net_assets,//净资产
            'money'=>$money,                //余额
            'market_value'=>$market_value,//市值
            'sum_income'=>$sum_income,//总盈亏
        ];
        $this->success('',$data);
    }
}